package quarto.controller.client.strategy;

import java.util.ArrayList;

import quarto.model.Board;
import quarto.model.Piece;

/**
 * Een slimme strategie<br />
 * - bij het kiezen van de locatie kijkt de strategie op welke plaats hij
 *   kan winnen, als dit niet mogelijk is kiest hij een willekeurige locatie<br />
 * - voor het bepalen van het stuk voor de tegenstander, kijkt de strategie
 *   of de tegenstander er mee zou kunnen winnen
 * @knows
 * - Client
 * @does
 * - Beste positie bepalen van huidige Piece van Player
 * - Beste Piece bepalen voor tegenstander
 */
public class PerfectStrategy extends Strategy 
{
    public static final String NAME = "Perfecte strategie";
    /**
     * het laatst geplaatste stuk
     */
    private Piece currentPiece;
    
    /**
     * de locatie van het laatst geplaatste stuk
     */
    private int currentLocation;
    
    /**
     * Maakt een strategie aan met bijbehorende naam
     */
    public PerfectStrategy()
    {
        this.name = PerfectStrategy.NAME;
    }
    
    /**
     * Geeft de beste locatie terug voor het opgegeven stuk
     * @param  piece het stuk waarmee gespeeld wordt
     * @return de beste locatie voor het meegegeven stuk
     */
    public int getLocationForPiece(Piece piece)
    {
        // deepcopy maken van het bord
        Board board = this.client.getBoard().deepCopy();
        
        // huidige stuk opslaan want die mag niet gebruikt worden bij getNewPiece()
        this.currentPiece = piece;
        
        // vraagt of er een positie is van een vakje waar het piece op gezet 
        // kan worden om te winnen. Als deze niet bestaat wordt het -1
        int bestLocation = getWinLocation(board, piece);
        
        // Er is geen winnende positie gevonden,
        // Kies een random locatie waarmee de tegenstander niet wint of
        // anders een random beschikbare locatie
        if (bestLocation == -1)
        {
            // alle beschikbare stukken
            ArrayList<Piece> availablePieces = board.getAvailablePieces();
            Piece tmpPiece;
            
            int[] posibilities = new int[Board.DIM * Board.DIM];
            int nrposibilities = 0;
            
            int i = 0;
            while (i < (Board.DIM * Board.DIM))
            {
                // als het een leeg vakje is, zetten we het stuk erop en gaan we
                // kijken hoe handig die locatie is
                if (board.isEmpty(i))
                {
                    // huidige stuk zetten
                    board.setPiece(i, piece);
                    
                    // boolean die aangeeft of er al een stuk gevonden is waarvoor geldt
                    // dat de tegenstander NIET kan winnen
                    boolean foundPiece = false;
                    int j = 0;
                    while (j < availablePieces.size() && !foundPiece)
                    {
                        tmpPiece = availablePieces.get(j);
                        
                        // tmpPiece is niet gelijk aan het huidige stuk en de tegenstander 
                        // kan niet winnen met tmpPiece. Dus we kiezen deze locatie. 
                        if (!this.currentPiece.compare(tmpPiece) &&
                            getWinLocation(board, tmpPiece) == -1)
                        {
                            // we hebben nog geen beste locatie, dus opslaan, of
                            // anders hebben we meerdere keuzes en gaan we random selecteren
                            //if (bestLocation == -1 || Math.random() > 0.7)
                            //{
                                //bestLocation = i;
                            //}
                            
                            posibilities[nrposibilities] = i;
                            nrposibilities++;
                            
                            foundPiece = true;
                        }
                        j++;
                    }
                    
                    // we halen het vakje weer leeg
                    board.setPiece(i, null);
                }
                i++;
            }
            
            if (nrposibilities > 0)
            {
                int rand = (int)(Math.random() * nrposibilities);
                bestLocation = posibilities[rand];
            }
        }
        
        // Er is geen locatie gevonden waarvoor geldt dat de tegenstander NIET kan
        // winnen met welk stuk dan ook, dus kiezen we een random leeg vakje en weten we
        // eigenlijk dat we gaan verliezen
        if (bestLocation == -1)
        {
            bestLocation = this.getRandomLocation();
        }
        
        return this.currentLocation = bestLocation;
    }
    
    /**
     * Geeft het stuk terug die de tegenstander moet plaatsen, 
     * bij voorkeur waar de tegenstander niet mee kan winnen
     * @return Piece het stuk wat de tegenstander moet plaatsen
     */
    public Piece getNewPiece()
    {
        // kopie van het board maken zodat er geen wijzigingen komen aan het originele bord
        Board board = this.client.getBoard().deepCopy();
        
        // het huidige stuk zetten op de gekozen locatie
        board.setPiece(this.currentLocation, this.currentPiece);
        
        // result
        Piece newPiece = null;
        
        // Alle beschikbare stukken opvragen van een deepCopy, zodat we geen 
        // ConcurrentModificationException krijgen
        ArrayList<Piece> availPieces = board.deepCopy().getAvailablePieces();
        
        // door de beschikbare stukken lussen
        for (Piece tmpPiece : availPieces)
        {
            // Indien de tegenstander niet kan winnen met dit stuk, 
            // dan is het een stuk dat we kunnen teruggeven
            if (this.getWinLocation(board, tmpPiece) == -1)
            {
                // er was nog geen newPiece gevonden, dus deze nemen we...
                // Er zijn meerder stukken die in aanmerking komen, dus 
                // we selecteren random
                if (newPiece == null || Math.random() > 0.7)
                {
                    newPiece = tmpPiece;
                }
            }
        }
        
        // De tegenstander wint, want met elk beschikbaar stuk kan de tegenstander
        // winnen. We kiezen dus een random beschikbaar stuk
        if (newPiece == null)
        {
            newPiece = this.getRandomPiece();
        }
        
        return newPiece;
    }
}
